<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>原生JS实现购物车结算功能代码</title>
    <link rel="stylesheet" href="../css/style.css" />
    <style>
        .goods span {
            display: block;

            display: -webkit-box;
            -webkit-box-orient: vertical;
            -webkit-line-clamp: 2;
            overflow: hidden;
            text-overflow: ellipsis;
        }
    </style>
</head>

<body>
    <div class="catbox">
        <table id="cartTable">
            <thead>
                <tr>
                    <th><label>
                            <input class="check-all check" type="checkbox" />&nbsp;&nbsp;全选</label></th>
                    <th>商品</th>
                    <th>单价</th>
                    <th>数量</th>
                    <th>小计</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <!-- <tr>
                    <td class="checkbox"><input class="check-one check" type="checkbox" /></td>
                    <td class="goods"><img src="../images/1.jpg" alt="" /><span>Casio/卡西欧 EX-TR350</span></td>
                    <td class="price">5999.88</td>
                    <td class="count"><span class="reduce"></span>
                        <input class="count-input" type="text" value="1" />
                        <span class="add">+</span>
                    </td>
                    <td class="subtotal">5999.88</td>
                    <td class="operation"><span class="delete">删除</span></td>
                </tr>
                <tr>
                    <td class="checkbox"><input class="check-one check" type="checkbox" /></td>
                    <td class="goods"><img src="../images/2.jpg" alt="" /><span>Canon/佳能 PowerShot SX50 HS</span></td>
                    <td class="price">3888.50</td>
                    <td class="count"><span class="reduce"></span>
                        <input class="count-input" type="text" value="1" />
                        <span class="add">+</span>
                    </td>
                    <td class="subtotal">3888.50</td>
                    <td class="operation"><span class="delete">删除</span></td>
                </tr>
                <tr>
                    <td class="checkbox"><input class="check-one check" type="checkbox" /></td>
                    <td class="goods"><img src="../images/3.jpg" alt="" /><span>Sony/索尼 DSC-WX300</span></td>
                    <td class="price">1428.50</td>
                    <td class="count"><span class="reduce"></span>
                        <input class="count-input" type="text" value="1" />
                        <span class="add">+</span>
                    </td>
                    <td class="subtotal">1428.50</td>
                    <td class="operation"><span class="delete">删除</span></td>
                </tr>
                <tr>
                    <td class="checkbox"><input class="check-one check" type="checkbox" /></td>
                    <td class="goods"><img src="../images/4.jpg" alt="" /><span>Fujifilm/富士 instax mini 25</span></td>
                    <td class="price">640.60</td>
                    <td class="count"><span class="reduce"></span>
                        <input class="count-input" type="text" value="1" />
                        <span class="add">+</span>
                    </td>
                    <td class="subtotal">640.60</td>
                    <td class="operation"><span class="delete">删除</span></td>
                </tr> -->
            </tbody>
        </table>
        <div class="foot" id="foot">

            <a class="fl" id="deleteAll" href="javascript:;">删除</a>
            <div class="fr closing" onclick="getTotal();">结 算</div>
            <input type="hidden" id="cartTotalPrice" />
            <div class="fr total">合计：￥<span id="priceTotal">0.00</span></div>
            <div class="fr selected" id="selected">已选商品<span id="selectedTotal">0</span>件<span
                    class="arrow up">︽</span><span class="arrow down">︾</span></div>
            <div class="selected-view">
                <div id="selectedViewList" class="clearfix">
                    <div><img src="../images/1.jpg"><span>取消选择</span></div>
                </div>
                <span class="arrow">◆<span>◆</span></span>
            </div>
        </div>
    </div>



</body>
<script>
    var tbody = document.querySelector("#cartTable tbody");

    // 请求数据并渲染
    let xhr = new XMLHttpRequest(); // 0

    xhr.open("get", "../data/shoppingCar.json", true); // 1

    xhr.send();  // 1

    xhr.onreadystatechange = function () {
        // 2 3 4
        // console.log("xhr.readyState改变了", xhr.readyState);
        if (xhr.readyState == 4 && xhr.status == 200) {
            var res = xhr.responseText;
            var data = JSON.parse(res);
            console.log("data", data);


            // 注意:
            // 模板字符串中 ${}不仅可以接收变量 =>将变量拼接到字符串中, 也开始接收js表达式(元素符 和 操作数(变量,常量)) 组成的式子

            var html = "";
            data.forEach(({ goodsId, goodsName, goodsImg, goodsPrice, buyNum }) => {
                html += ` <tr>
                    <td class="checkbox"><input class="check-one check" type="checkbox" /></td>
                    <td class="goods"><img src="${goodsImg}" alt="" /><span>${goodsName}</span></td>
                    <td class="price">${goodsPrice}</td>
                    <td class="count"><span class="reduce">${buyNum > 1 ? "-" : ""}</span>
                        <input class="count-input" type="text" value="${buyNum}" />
                        <span class="add">+</span>
                    </td>
                    <td class="subtotal">${(goodsPrice * buyNum).toFixed(2)}</td>
                    <td class="operation"><span class="delete">删除</span></td>
                </tr>`
            })

            // 前
            tbody.innerHTML = html;  // 动态生成
            // 后

            // 获取元素绑定事件 
            var checkAll = document.getElementsByClassName("check-all")[0];  // 单元素
            var checkOneList = document.getElementsByClassName("check-one");  // 多元素
            var addList = document.getElementsByClassName("add");
            var reduceList = document.getElementsByClassName("reduce");
            var delList = document.getElementsByClassName("delete");
            var deleteAll = document.getElementById("deleteAll");
            var selectedTotal = document.getElementById("selectedTotal");
            var priceTotal = document.getElementById("priceTotal");

            console.log("checkOneList", checkOneList);
            console.log("addList", addList);
            console.log("delList", delList);


            //  全选  => 点击全选  所有单选框(check-one)的状态跟随全选(check-all)的状态 (checked)
            //  1. 获取全选的状态
            //  2. 所有单选的状态和全选保持一致 
            checkAll.onclick = function () {
                var status = this.checked;
                console.log("点击全选", status);

                // for(var i = 0;i<checkOneList.length;i++){
                //     var checkOne = checkOneList[i];
                //     checkOne.checked = status;
                // }

                Array.from(checkOneList).forEach(function (checkOne) {
                    checkOne.checked = status;
                })

                getTotal();

            }


            // 反选  => 每次点击单选  =>  判断所有的单选是否都选中  => 全都选选中 :全选反选  否则:全选不选中

            for (var i = 0; i < checkOneList.length; i++) {
                var checkOne = checkOneList[i];
                checkOne.onclick = function () {
                    // 如何判断所有的单选是否都被选中? 

                    // 每次点击点选判断 
                    isAllChecked();
                    getTotal();





                }
            }


            //  (1)加法要求 
            // 点击 “+”     输入框  数量 加一 
            //             小计更新  =  单价*数量
            //             减号按钮的 “-”  出现
            for (var i = 0; i < addList.length; i++) {
                var add = addList[i];
                add.onclick = function () {
                    console.log("加号被点击", this);

                    // a. 输入框  数量 加一 
                    var countInput = this.previousElementSibling;
                    console.log(countInput);

                    var num = countInput.value; // num = "1"   取值
                    num++; // 自增
                    countInput.value = num; // 赋值(更新到页面)

                    // b. 小计更新  =  单价*数量
                    // 数量 => num
                    // 单价 => 

                    var parentTd = this.parentElement;
                    var priceTd = parentTd.previousElementSibling;
                    var subtotalTd = parentTd.nextElementSibling;

                    // "¥5999"  "5999元" => 如果有单位 需要进一步处理
                    var price = priceTd.textContent;
                    var subtotal = price * num;

                    subtotalTd.textContent = subtotal.toFixed(2);


                    // c. 减号按钮的 “-”  出现
                    var reduce = countInput.previousElementSibling;
                    reduce.textContent = "-";


                    getTotal()

                }
            }


            // 点击减号    输入框  数量 减一   （细节要求  数量为1的时候  不再减）
            //            小计更新  =  单价*数量 
            //            减之前  判断  如果数量为1  不能减     return false
            //            减之后  判断  如果数量为1  减号按钮的 “-” 消失

            for (var i = 0; i < reduceList.length; i++) {
                var reduce = reduceList[i];
                reduce.onclick = function () {
                    console.log("减号被点击", this);
                    // a. 输入框  数量 减一 
                    var countInput = next(this);
                    var num = countInput.value;

                    // c. 减之前判断 如果num == 1 不能减
                    if (num == 1) return false;

                    num--; // 自减

                    // d. 减之后判断 如果 num == 1 (2切1) 减号按钮的 "-" 消失
                    if (num == 1) {
                        this.textContent = "";
                    }

                    countInput.value = num;

                    // b. 小计更新  =  单价*数量
                    // 数量 => num
                    // 单价 => 

                    var parentTd = parent(this);
                    var priceTd = prev(parentTd);
                    var subtotalTd = next(parentTd);

                    var price = priceTd.textContent;
                    var subtotal = price * num;
                    subtotalTd.textContent = subtotal.toFixed(2);

                    getTotal()
                }
            }


            // 删除细节
            // a. 单删 => 每次删除之后,剩余的商品可能全都被选中 此时也可以反选 => 也需要判断是否反选
            // b. 全删 => 所有商品选中后全部删除(单删/全删), 全选依然被选中 =>  原因:商品全部删除之后checkOneList.length == 0 => 此时不会进入循环 假设法有问题 => flag = true;
            // 解决方法:  商品数 > 0  采用假设法,否则 false 

            // 3.  再写删除 
            // 1.  单删   点击每条数据之后的删除   删除该条数据
            for (var i = 0; i < delList.length; i++) {
                var del = delList[i];
                del.onclick = function () {
                    console.log("点击单删", this);

                    if (confirm("是否删除商品?")) {
                        // var tr = this.parentElement.parentElement;
                        var tr = parent(parent(this));
                        tr.remove();

                        // 每次删除之后,剩余的商品可能全都被选中 此时也可以反选 => 也需要判断是否反选
                        isAllChecked();
                        getTotal();

                    }

                }
            }

            // 2.  多删(全删)   判断单选框是否被选中(checked)     选中就删除 该行  

            // 全删的问题: 删除过程中存在漏网之鱼      
            // 解析: 全面的tr被删除之后,checkOneList更新 => 后面的元素会批量向前移占据被删除元素的位置 => 删除时可能错过某些元素
            // j       0       1        2        3 
            //    [checkOne,checkOne,checkOne,checkOne]    

            deleteAll.onclick = function () {
                // 删除所有选中状态的商品
                for (var j = 0; j < checkOneList.length; j++) { // 假设 j=1时 checkOne被选中
                    var checkOne = checkOneList[j];
                    if (checkOne.checked) {
                        var tr = parent(parent(checkOne));
                        tr.remove();
                        j--;  //  j-- => j=0  本次循环结束  j++ => j = 1  下次还从当前位置判断
                    }
                }

                isAllChecked();
                getTotal();
            }



            function isAllChecked() {
                // 假设法  => 先立一个假设(flag),然后尝试从对立面推翻它,  => 推翻了,假设不成立 没推翻=> 成立
                // var flag = true; // 假设全都被选中(假设)
                // // 然后尝试从对立面推翻它  => 有一个未选中的就可以推翻假设
                // for(var j=0;j<checkOneList.length;j++){
                //     var item = checkOneList[j];  // 每一个单选
                //     // item.checked == false
                //     // !item.checked == true => 才满足条件 => 取反前item.checked === false
                //     if(!item.checked){  // 存在未选中的 
                //         flag = false;  // 推翻假设
                //         break;
                //     }
                // }
                // checkAll.checked = flag;

                // every版  => 判断是否都选中
                var flag = Array.from(checkOneList).every(function (item) {
                    return item.checked == true;
                })
                checkAll.checked = checkOneList.length > 0 ? flag : false;
            }


            // 结算=> 找到所有选中状态的checkOne => 对应找到商品的数量和小计 => 累加
            function getTotal() {
                var sum = 0; // 商品数量之和
                var allPrice = 0; // 商品的合计
                for (var j = 0; j < checkOneList.length; j++) {
                    var checkOne = checkOneList[j];
                    if (checkOne.checked) {  // 如果checkOne被选中  

                        // 对应找到商品的数量和小计 
                        var tr = parent(parent(checkOne));
                        var countInput = tr.getElementsByClassName("count-input")[0];
                        var subtotalTd = tr.getElementsByClassName("subtotal")[0];

                        var num = countInput.value * 1;
                        var subtotal = subtotalTd.textContent * 1;

                        sum += num;
                        allPrice += subtotal;

                    }
                }
                selectedTotal.textContent = sum;
                priceTotal.textContent = allPrice.toFixed(2);
            }

        }
    }


    // 问题: ajax请求时异步的, 浏览器不会等待ajax请求结束,而是先把异步任务放到 WebAPI中, 监听xhr.readyState的改变, 与此同时同步代码继续向后执行 => 此时ajax数据还未请求到 => 商品数据也未生产  => 此时,获取动态生成的元素绑定事件时 => 集合为[] => 没有给任何一个元素绑定事件

    // 解决方法: 
    // 1. 老赖行为 =>  等ajax请求完毕 数据动态生成之后  在获取元素和绑定事件







    function parent(ele) {
        return ele.parentElement;
    }

    function prev(ele) {
        return ele.previousElementSibling;
    }

    function next(ele) {
        return ele.nextElementSibling;
    }




</script>

</html>